# SPDX-License-Identifier: GPL-3.0-only
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2023-2024 Leah Rowe <leah@libreboot.org>

e6400_unpack="$PWD/src/bios_extract/dell_inspiron_1100_unpacker.py"
me7updateparser="$PWD/util/me7_update_parser/me7_update_parser.py"
pfs_extract="$PWD/src/biosutilities/Dell_PFS_Extract.py"
uefiextract="$PWD/elf/uefitool/uefiextract"
appdir="vendorfiles/app"
cbcfgsdir="config/coreboot"

eval `setvars "" EC_url_bkup EC_hash DL_hash DL_url_bkup MRC_refcode_gbe vcfg \
    E6400_VGA_DL_hash E6400_VGA_DL_url E6400_VGA_DL_url_bkup E6400_VGA_offset \
    E6400_VGA_romname CONFIG_HAVE_MRC SCH5545EC_DL_url_bkup SCH5545EC_DL_hash \
    mecleaner kbc1126_ec_dump MRC_refcode_cbtree _dl SCH5545EC_DL_url _7ztest \
    CONFIG_BOARD_DELL_E6400 CONFIG_HAVE_ME_BIN EC_url CONFIG_REFCODE_BLOB_FILE \
    CONFIG_ME_BIN_PATH CONFIG_KBC1126_FIRMWARE _dest tree CONFIG_GBE_BIN_PATH \
    CONFIG_KBC1126_FW1_OFFSET CONFIG_KBC1126_FW2 CONFIG_KBC1126_FW2_OFFSET rom \
    CONFIG_VGA_BIOS_FILE CONFIG_VGA_BIOS_ID CONFIG_KBC1126_FW1 cbdir DL_url \
    CONFIG_INCLUDE_SMSC_SCH5545_EC_FW CONFIG_SMSC_SCH5545_EC_FW_FILE boarddir \
    CONFIG_IFD_BIN_PATH CONFIG_MRC_FILE CONFIG_HAVE_REFCODE_BLOB cbfstoolref`

vendor_download()
{
	export PATH="$PATH:/sbin"

	[ $# -gt 0 ] || $err "No argument given"
	board="$1" && readcfg && readkconfig && bootstrap && getfiles; return 0
}

readcfg()
{
	boarddir="$cbcfgsdir/$board"
	eval `setcfg "$boarddir/target.cfg"`; chkvars vcfg tree

	cbdir="src/coreboot/$tree"
	cbfstool="elf/cbfstool/$tree/cbfstool"
	mecleaner="$PWD/$cbdir/util/me_cleaner/me_cleaner.py"
	kbc1126_ec_dump="$PWD/$cbdir/util/kbc1126/kbc1126_ec_dump"
	cbfstool="elf/cbfstool/$tree/cbfstool"

	x_ ./update trees -d coreboot $tree
}

readkconfig()
{
	check_defconfig "$boarddir" 1>"$TMPDIR/vendorcfg.list" && return 1
	while read -r cbcfgfile; do
		set +u +e; . "$cbcfgfile" 2>/dev/null; set -u -e
	done < "$TMPDIR/vendorcfg.list"

	for c in CONFIG_HAVE_MRC CONFIG_HAVE_ME_BIN CONFIG_KBC1126_FIRMWARE \
	    CONFIG_VGA_BIOS_FILE CONFIG_INCLUDE_SMSC_SCH5545_EC_FW; do
		eval "[ \"\${$c}\" = \"/dev/null\" ] && continue"
		eval "[ -z \"\${$c}\" ] && continue"
		eval `setcfg "config/vendor/$vcfg/pkg.cfg"`; return 0
	done
	printf "Vendor files not needed for: %s\n" "$board" 1>&2; return 1
}

bootstrap()
{
	x_ ./update trees -f coreboot ${cbdir##*/}
	for d in uefitool biosutilities bios_extract; do
		x_ ./update trees -b "$d"
	done
	[ -d "${kbc1126_ec_dump%/*}" ] && x_ make -C "$cbdir/util/kbc1126"
	[ -n "$MRC_refcode_cbtree" ] && \
	    cbfstoolref="elf/cbfstool/$MRC_refcode_cbtree/cbfstool" && \
	    x_ ./update trees -d coreboot $MRC_refcode_cbtree; return 0
}

getfiles()
{
	[ -z "$CONFIG_HAVE_ME_BIN" ] || fetch intel_me "$DL_url" \
	    "$DL_url_bkup" "$DL_hash" "$CONFIG_ME_BIN_PATH"
	[ -z "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" ] || fetch sch5545ec \
	    "$SCH5545EC_DL_url" "$SCH5545EC_DL_url_bkup" "$SCH5545EC_DL_hash" \
	    "$CONFIG_SMSC_SCH5545_EC_FW_FILE"
	[ -z "$CONFIG_KBC1126_FIRMWARE" ] || fetch kbc1126ec "$EC_url" \
	    "$EC_url_bkup" "$EC_hash" "$CONFIG_KBC1126_FW1"
	[ -z "$CONFIG_VGA_BIOS_FILE" ] || fetch "e6400vga" \
	    "$E6400_VGA_DL_url" "$E6400_VGA_DL_url_bkup" "$E6400_VGA_DL_hash" \
	    "$CONFIG_VGA_BIOS_FILE"
	[ -z "$CONFIG_HAVE_MRC" ] || fetch "mrc" "$MRC_url" "$MRC_url_bkup" \
	    "$MRC_hash" "$CONFIG_MRC_FILE"; return 0
}

fetch()
{
	dl_type="$1"; dl="$2"; dl_bkup="$3"; dlsum="$4"; _dest="${5##*../}"
	[ "$5" = "/dev/null" ] && return 0; _dl="$XBMK_CACHE/file/$dlsum"

	download "$dl" "$dl_bkup" "$_dl" "$dlsum"

	rm -Rf "${_dl}_extracted" || \
	    $err "!rm -Rf ${_ul}_extracted"
	e "$_dest" f && return 0

	mkdir -p "${_dest%/*}" || $err "mkdirs: !mkdir -p ${_dest%/*}"
	remkdir "$appdir"
	extract_archive "$_dl" "$appdir" || [ "$dl_type" = "e6400vga" ] || \
	    $err "mkdirs $_dest $dl_type: !extract"

	eval "extract_$dl_type"; set -u -e
	e "$_dest" f missing && $err "!extract_$dl_type"; return 0
}

extract_intel_me()
{
	e "$mecleaner" f not && $err "$cbdir: me_cleaner missing"

	_me="$PWD/$_dest" # must always be an absolute path
	cdir="$PWD/$appdir" # must always be an absolute path
	[ $# -gt 0 ] && _me="${1}" && cdir="$2"

	e "$_me" f && return 0

	sdir="$(mktemp -d)"; [ -z "$sdir" ] && return 0
	mkdir -p "$sdir" || $err "extract_intel_me: !mkdir -p \"$sdir\""

	set +u +e
	(
	[ "${cdir#/a}" != "$cdir" ] && cdir="${cdir#/}"
	cd "$cdir" || $err "extract_intel_me: !cd \"$cdir\""
	for i in *; do
		[ -f "$_me" ] && break
		[ -L "$i" ] && continue
		if [ -f "$i" ]; then
			"$mecleaner" -r -t -O "$sdir/vendorfile" \
			    -M "$_me" "$i" && break
			"$mecleaner" -r -t -O "$_me" "$i" && break
			"$me7updateparser" -O "$_me" "$i" && break
			_7ztest="${_7ztest}a"
			extract_archive "$i" "$_7ztest" || continue
			extract_intel_me "$_me" "$cdir/$_7ztest"
		elif [ -d "$i" ]; then
			extract_intel_me "$_me" "$cdir/$i"
		else
			continue
		fi
		cdir="$1"
		[ "${cdir#/a}" != "$cdir" ] && cdir="${cdir#/}"
		cd "$cdir" || :
	done
	)
	rm -Rf "$sdir" || $err "extract_intel_me: !rm -Rf $sdir"
}

extract_archive()
{
	innoextract "$1" -d "$2" || python "$pfs_extract" "$1" -e || 7z x \
	    "$1" -o"$2" || unar "$1" -o "$2" || unzip "$1" -d "$2" || return 1
}

extract_kbc1126ec()
{
	e "$kbc1126_ec_dump" f missing && $err "$cbdir: kbc1126 util missing"
	(
	x_ cd "$appdir/"; mv Rompaq/68*.BIN ec.bin || :
	if [ ! -f "ec.bin" ]; then
		unar -D ROM.CAB Rom.bin || unar -D Rom.CAB Rom.bin || \
		    unar -D 68*.CAB Rom.bin || $err "can't extract Rom.bin"
		x_ mv Rom.bin ec.bin
	fi
	[ -f ec.bin ] || $err "extract_kbc1126_ec $board: can't extract"
	"$kbc1126_ec_dump" ec.bin || $err "!1126ec $board extract ecfw"
	) || $err "can't extract kbc1126 ec firmware"

	e "$appdir/ec.bin.fw1" f not && $err "$board: kbc1126ec fetch failed"
	e "$appdir/ec.bin.fw2" f not && $err "$board: kbc1126ec fetch failed"

	cp "$appdir/"ec.bin.fw* "${_dest%/*}/" || $err "!cp 1126ec $_dest"
}

extract_e6400vga()
{
	set +u +e; chkvars E6400_VGA_offset E6400_VGA_romname
	tail -c +$E6400_VGA_offset "$_dl" | gunzip > "$appdir/bios.bin" || :
	(
	x_ cd "$appdir"
	[ -f "bios.bin" ] || $err "extract_e6400vga: can't extract bios.bin"
	"$e6400_unpack" bios.bin || printf "TODO: fix dell extract util\n"
	) || $err "can't extract e6400 vga rom"
	cp "$appdir/$E6400_VGA_romname" "$_dest" || $err "64 !cp $board $_dest"
}

extract_sch5545ec()
{
	# full system ROM (UEFI), to extract with UEFIExtract:
	_bios="${_dl}_extracted/Firmware/1 $dlsum -- 1 System BIOS vA.28.bin"
	# this is the SCH5545 firmware, inside of the extracted UEFI ROM:
	_sch5545ec_fw="$_bios.dump/4 7A9354D9-0468-444A-81CE-0BF617D890DF"
	_sch5545ec_fw="$_sch5545ec_fw/54 D386BEB8-4B54-4E69-94F5-06091F67E0D3"
	_sch5545ec_fw="$_sch5545ec_fw/0 Raw section/body.bin" # <-- this!

	"$uefiextract" "$_bios" || $err "sch5545 !extract"
	cp "$_sch5545ec_fw" "$_dest" || $err "$_dest: !sch5545 copy"
}
